﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Microsoft.Kinect;
using System.Xml;
using System.Xml.Serialization;
using Microsoft.Win32;
using System.IO;
using System.Windows.Markup;

namespace WpfKinectUserControls
{
     [XmlRoot("KinectParameters")]
    public class KinectParamsSerializable
    {
        public float Smoothing;
        public float Correction;
        public float Prediction;
        public float JitterRadius;
        public float MaxDeviationRadius;
        public static void Serialize(String sFilename, KinectParamsSerializable obj)
        {
            XmlSerializer xmls = new XmlSerializer(typeof(KinectParamsSerializable));
            using (TextWriter w = new StreamWriter(sFilename))
            {
                xmls.Serialize(w, obj);
            }
        }
        public static KinectParamsSerializable Deserialize(String sFileName)
        {
            KinectParamsSerializable obj;
            XmlSerializer xmls = new XmlSerializer(typeof(KinectParamsSerializable));
            using (TextReader w = new StreamReader(sFileName))
            {
                obj = (KinectParamsSerializable)xmls.Deserialize(w);
                w.Close();
            }
            return obj;
        }
    }
    /// <summary>
    /// Interaction logic for KinectFilteringParamsControl.xaml
    /// </summary>
   
    public partial class KinectFilteringParamsControl : UserControl
    {
        public static readonly DependencyProperty SmoothingProperty =
            DependencyProperty.Register("Smoothing", typeof(float),
            typeof(KinectFilteringParamsControl), new FrameworkPropertyMetadata(float.MinValue));   
        public static readonly DependencyProperty CorrectionProperty =
            DependencyProperty.Register("Correction", typeof(float),
            typeof(KinectFilteringParamsControl), new FrameworkPropertyMetadata(float.MinValue));
        public static readonly DependencyProperty PredictionProperty =
            DependencyProperty.Register("Prediction", typeof(float),
            typeof(KinectFilteringParamsControl), new FrameworkPropertyMetadata(float.MinValue));
        public static readonly DependencyProperty JitterRadiusProperty =
            DependencyProperty.Register("JitterRadius", typeof(float),
            typeof(KinectFilteringParamsControl), new FrameworkPropertyMetadata(float.MinValue));
        public static readonly DependencyProperty MaxDeviationRadiusProperty =
            DependencyProperty.Register("MaxDeviationRadius", typeof(float),
            typeof(KinectFilteringParamsControl), new FrameworkPropertyMetadata(float.MinValue));
        public static readonly DependencyProperty CurrentKinectSensorProperty =
            DependencyProperty.Register("CurrentKinectSensor", typeof(KinectSensor),
            typeof(KinectFilteringParamsControl), new PropertyMetadata(new PropertyChangedCallback(OnCurrentKinectSensorChanged)));

        public float Smoothing
        {
            get { return (float)GetValue(SmoothingProperty); }
            set { SetValue(SmoothingProperty, value); }
        }
        public float Correction
        {
            get { return (float)GetValue(CorrectionProperty); }
            set { SetValue(CorrectionProperty, value); }
        }
        public float Prediction
        {
            get { return (float)GetValue(PredictionProperty); }
            set { SetValue(PredictionProperty, value); }
        }
        public float JitterRadius
        {
            get { return (float)GetValue(JitterRadiusProperty); }
            set { SetValue(JitterRadiusProperty, value); }
        }
        public float MaxDeviationRadius
        {
            get { return (float)GetValue(MaxDeviationRadiusProperty); }
            set { SetValue(MaxDeviationRadiusProperty, value); }
        }
        
        public KinectSensor CurrentKinectSensor
        {
            get { return (KinectSensor)GetValue(CurrentKinectSensorProperty); }
            set { SetValue(CurrentKinectSensorProperty, value); }
        }

        public KinectFilteringParamsControl()
        {
            InitializeComponent();
        }

        private float LimitFloatTo(float value, float min, float max)
        {
            if (value < min) return min;
            if (value >= max) return max;
            return value;
        }

        private static void OnCurrentKinectSensorChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var value = e.NewValue;

            ((KinectFilteringParamsControl)d).IsEnabled = value != null;
        }
        private void uc_Loaded(object sender, RoutedEventArgs e)
        {
            this.IsEnabled = false;
        }
        private void Button_Click(object sender, RoutedEventArgs e)
        {
            Smoothing = LimitFloatTo(Smoothing, 0f, 0.99f);
            Correction = LimitFloatTo(Correction, 0f, 0.99f);
            Prediction = LimitFloatTo(Prediction, 0f, 10000f);
            MaxDeviationRadius = LimitFloatTo(MaxDeviationRadius, 0f, 10000f);
            JitterRadius = LimitFloatTo(JitterRadius, 0f, 10000f);
            
            if(CurrentKinectSensor!=null)
            {
                if (CurrentKinectSensor.SkeletonStream.IsEnabled)
                {
                    CurrentKinectSensor.SkeletonStream.Disable();
                    TransformSmoothParameters tsp = new TransformSmoothParameters();
                    tsp.Smoothing = this.Smoothing;
                    tsp.Correction = this.Correction;
                    tsp.Prediction = this.Prediction;
                    tsp.JitterRadius = this.JitterRadius;
                    tsp.MaxDeviationRadius = this.MaxDeviationRadius;
                    CurrentKinectSensor.SkeletonStream.Enable(tsp);
                }
            }
        }

        //Deserialize parameters from XML file to the object
        private void Button_XMLOpen(object sender, RoutedEventArgs e)
        {
            OpenFileDialog ofDlg = new OpenFileDialog();
            ofDlg.Filter = "XML Files (.xml)|*.xml";
            ofDlg.FilterIndex = 1;
            ofDlg.Multiselect = false;
            bool? isOK = ofDlg.ShowDialog();
            if (isOK == true)
            {
                KinectParamsSerializable ksp = KinectParamsSerializable.Deserialize(ofDlg.FileName);
                if (ksp!=null)
                {
                    this.Smoothing = ksp.Smoothing;
                    this.Correction = ksp.Correction;
                    this.Prediction = ksp.Prediction;
                    this.JitterRadius = ksp.JitterRadius;
                    this.MaxDeviationRadius = ksp.MaxDeviationRadius;
                }
            }
        }
        //Serialize parameters from object to XML file
        private void Button_XMLSave(object sender, RoutedEventArgs e)
        {
            SaveFileDialog ofDlg = new SaveFileDialog();
            ofDlg.Filter = "XML Files (.xml)|*.xml";
            ofDlg.FilterIndex = 1;
            bool? isOK = ofDlg.ShowDialog();
            if (isOK == true)
            {
                KinectParamsSerializable ksp = new KinectParamsSerializable() { Smoothing = this.Smoothing, Correction = this.Correction, JitterRadius = this.JitterRadius, MaxDeviationRadius = this.MaxDeviationRadius, Prediction = this.Prediction };
                KinectParamsSerializable.Serialize(ofDlg.FileName, ksp);
            }
        }
    }
}
